from ..errors import CardGameError, UnimplementedError
from ..errors import NoSuchUserError, NoSuchCardError, NoSuchCollectionError

class CardCollectionError(CardGameError):
    """
    Parent class for all errors in this module.
    """
    
class DuplicateCardError(CardCollectionError):
    """
    Generated when an attempt is made to add a card 
    to a collection that already contains that card.
    """

class CardCollectionController(object):
    """
    Controls a collection of cards (e.g. a hand or
     a table) and its data storage, as specifically 
    implemented by its descendants.
    """
    def __init__(self, cards, args):
        """
        Usage: CardCollectionController(cards)
        Takes a dictionary pairing card IDs to 
        dictionaries of arguments and a dictionary 
        of implementation-specific arguments.
        """
        pass
        
    def in_collection(self, card_id):
        """
        Returns True if the card indicated is contained 
        within this collection.
        """
        raise UnimplementedError(self)
        
    def remove_card(self, card_id):
        """
        Removes the card from this collection.
        """
        raise UnimplementedError(self)
    
    def add_card(self, card_id, args):
        """
        Adds a card to the collection with details 
        specified in a dictionary of arguments 
        (e.g. coordinates, face-up vs. face-down)
        
        Raises an exception if the card is 
        already in the collection/
        """
        raise UnimplementedError(self)  
    
class InMemoryCardCollectionController(CardCollectionController):
    """
    A collection that generates and stores a sample card 
    database in memory.
    
    Provided for testing purposes only.
    """
    
    def __init__(self, cards, args):
        """
        Takes a dictionary of arguments keyed to 
        card IDs.
        Ignores 'args'.
        """
        self.cards = cards
        
    def in_collection(self, card_id):
        if card_id in self.cards.keys():
            return True
        else:
            return False
        
    def remove_card(self, card_id):
        if card_id in self.cards.keys():
            del self.cards[card_id]
            return True
        else:
            raise NoSuchCardError(card_id)
        
    def add_card(self, card_id, args):
        if card_id in self.cards.keys():
            raise DuplicateCardError(card_id)
            return True
        else:
            self.cards[card_id] = args